﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Toolkit.Web.Infastructure
{
    public sealed class HtmlNode : IHtmlNode
    {
        private TagBuilder _tagBuilder;

        public HtmlNode(string tagName)
            : this(tagName, TagRenderMode.Normal)
        {
        }

        public HtmlNode(string tagName, TagRenderMode renderMode)
        {
            _tagBuilder = new TagBuilder(tagName);
            RenderMode = renderMode;
            Children = new List<IHtmlNode>();
        }

        public string TagName
        {
            get
            {
                return _tagBuilder.TagName;
            }
        }

        public string InnerHtml
        {
            get
            {
                return _tagBuilder.InnerHtml;
            }
            set
            {
                _tagBuilder.InnerHtml = value;
                Children.Clear();
            }
        }

        public TagRenderMode RenderMode
        {
            get;
            private set;
        }

        public IList<IHtmlNode> Children
        {
            get;
            private set;
        }

        public IDictionary<string, string> Attributes
        {
            get
            {
                return _tagBuilder.Attributes;
            }
        }

        public Action<IViewComponentWriter> Template
        {
            get;
            set;
        }

        public void ApplyTemplate(HtmlTemplate template)
        {
            template.Apply(this);
        }

        public void ApplyTemplate<T>(HtmlTemplate<T> template, T dataItem) where T : class
        {
            template.Apply(dataItem, this);
        }

        public void AppendTo(IHtmlNode parent)
        {
            parent.Children.Add(this);
        }

        public void Append(IHtmlNode child)
        {
            Children.Add(child);
        }

        public void WriteTo(IViewComponentWriter writer)
        {
            if (RenderMode != TagRenderMode.SelfClosing)
            {
                writer.Write(_tagBuilder.ToString(TagRenderMode.StartTag));

                if (Template != null)
                {
                    Template(writer);
                }
                else if (Children.Count > 0)
                {
                    foreach (IHtmlNode tag in Children)
                    {
                        tag.WriteTo(writer);
                    }
                }
                else
                {
                    writer.Write(_tagBuilder.InnerHtml);
                }

                writer.Write(_tagBuilder.ToString(TagRenderMode.EndTag));
            }
            else
            {
                writer.Write(_tagBuilder.ToString(TagRenderMode.SelfClosing));
            }
        }

        public override string ToString()
        {
            using (StringWriter output = new StringWriter())
            {
                WriteTo(new ViewComponentWriter(output));
                return output.ToString();
            }
        }

        public string ToString(IFormatProvider format)
        {
            using (var output = new StringWriter(format))
            {
                WriteTo(new ViewComponentWriter(output));
                return output.ToString();
            }
        }

        public void AddClass(params string[] classes)
        {
            foreach (string @class in classes)
            {
                _tagBuilder.AddCssClass(@class);
            }
        }

        public void AddStyle(string key, string value)
        {
            string style = string.Format("{0}:{1};", key, value);

            string currentStyles;
            if (Attributes.TryGetValue("style", out currentStyles))
            {
                if (!currentStyles.EndsWith(";"))
                {
                    currentStyles += ";";
                }

                Attributes["style"] = currentStyles + style;
            }
            else
            {
                Attributes["style"] = style;
            }
        }

        public void MergeAttribute(string key, string value, bool replaceExisting)
        {
            _tagBuilder.MergeAttribute(key, value, replaceExisting);
        }

        public void MergeAttributes<TKey, TValue>(IDictionary<TKey, TValue> values, bool replaceExisting)
        {
            _tagBuilder.MergeAttributes(values, replaceExisting);
        }
    }
}
